import {escapeCss} from './dom.js';
export {compileCss, addUnoCss, loadUno};
/**
 * 按列布局元素，可以指定宽度为百分比
 *
 *- 可以指定任何其他的属性
 *- toc元素默认尺寸和布局：`height:95vh;position:sticky;top:2.5vh;`，可以覆盖该配置
 *
 * @param {{selector: string, width: string, order?: number, isToc?:boolean, height?: string}[]} elements 所有列元素的配置
 * @param {string} elements.selector 列元素的选择器，注意不要使用`>`直接孩子选择器，因为被容器包裹后会失效
 * @param {string} elements.width 列的宽度，建议使用响应式的单位，比如`%`(相对父容器)和`vw`,`vh`(相对窗口)
 * @param {string?} containerSelector 可选的容器元素，如果不提供，则创建一个包裹所有elements中的元素，
 *                                    并且容器会被添加上一个css类：viocha-columns-container
 * @param {object?}containerCss 容器元素的可选样式
 * @returns {HTMLElement} 包裹的容器元素
 */
export function layoutColumns(elements, containerSelector, containerCss){
	let cssText = '';
	const $container = containerSelector? $(containerSelector): $('<div>');
	$container.addClass('viocha-columns-container');
	
	// 修改body的overflow，让position:sticky 生效！
	addCss('html body', {
		'overflow':'revert',
	});
	
	// flex容器的样式
	addCss('.viocha-columns-container', {
		'display':'flex', //
		'flex-direction':'row', //
		'gap':'1em', // 每列的缝隙
		'width':'100%', 'min-width':'revert', 'max-width':'revert', // 容器宽度撑满
		'margin':'0 auto', // 居中
		'padding':'0 0.5em', // 更清楚地看到左右边缘文字
		'overflow':'revert', // 让sticky生效
	});
	
	if (containerCss){
		addCss('.viocha-columns-container', containerCss);
	}
	
	const children = elements.map(config=>{
		const {selector, width, order, isToc, height} = config;
		delete config.selector, delete config.width, delete config.order, delete config.isToc, delete config.height;
		
		const $col = $(selector);
		/* =================所有列的通用样式========== */
		addCss(selector, {
			'width':width, 'min-width':'revert', // 设置宽度，并取消最小宽度
			'flex':'none', // 禁止伸缩
			'padding':'0', // 取消内边距
		});
		if (order){
			addCss(selector, {'order':order});
		} // 指定列的顺序
		if (height){
			addCss(selector, {
				'height':height, 'max-height':'revert', 'min-height':'revert', // 指定高度
			});
		}
		
		/* ===========================TOC列==========================*/
		if (isToc){
			addCss(selector, {
				'position':'sticky',//
				'top':'2.5vh', //
				'max-width':'30em', // 限制最大宽度
				'margin':'0', // TOC取消margin，固定到最右侧
				'padding-bottom':'2em', // 方便查看最后一个条目
				'overflow':'auto',//
			});
			
			if (!height){
				addCss(selector, {
					'height':'95vh', 'min-height':'revert', 'max-height':'revert', // toc默认95vh高度
				});
			}
			
			/* ========TOC内部元素(参考buildToc里面的样式)======== */
			addCss(`${selector} *`, {'overflow':'hidden'}); // 限制只有一个滚动条
			addCss(`${selector} :is(li,summary)`, {
				'min-width':'max-content', // toc的项，不换行
			});
			addCss(`${selector} :is(li,summary,a)`, {
				'font-size':'13px', // 字体大小和行高
				'line-height':'1.2',
			});
			addCss(`${selector} a`, {
				'display':'block', // 链接宽度撑满
				'text-decoration':'none', // 去掉链接的下划线
			});
			addCss(`${selector} a:hover`, {
				'background-color':'#ebf8f6', // 鼠标悬停时高亮
				'text-decoration-line':'underline', //
				'font-weight':'bold',
			});
		} else {
			/* ===========================内容列=========================== */
			addCss(selector, {
				'display':'block', //
				'max-width':'65em', /* 限制内容区最大宽度 */
				'margin':'0 auto', /* 内容列水平居中 */
			});
		}
		
		/* =============该列另外指定的css属性=============== */
		if (Object.keys(config).length>0){
			addCss(selector, config);
		}
		
		return $col[0];
	});
	// 如果children全是$container的孩子，那么不进行操作，这样能保留点击事件
	if ($container.children().filter(children).length!==children.length) //
	{
		$(children).wrapAll($container);
	}
	
	GM_addStyle(cssText);
	return $container[0];
	
	// 给selector添加important的样式
	function addCss(selector, attrs){
		cssText += `
			${selector}{
			  ${Object.entries(attrs)
								.map(([key, value])=>`${key}: ${value} !important;`)
								.join('\n')}
			}
		`;
	}
}

/**
 * 使用ul和li，生成大纲嵌套列表，默认取消列表标记以及li的缩进，使用ul嵌套产生缩进<br>
 * 每个ul都添加了`vicoha-toc`类，根节点添加了`viocha-toc-root`类，每个li添加了`viocha-toc-item`类<br>
 * 该函数还能处理层级序列有跳跃的序列，比如 1 3 3 2 3 ，对于中间不存在的层级，会自动补齐，但是对于大于等于7的层级不会补全
 *
 * @param {()=>HTMLElement[]}  getItems 返回所有的大纲项，顺序为dfs的先序顺序。如果items为空，则返回一个空ul
 * @param {(HTMLElement)=>number}  getLevel 返回大纲项的层级，所有层级应该是连续的整数，从1开始，例如h1-h6为1-6
 * @param {(HTMLElement)=>string}  getTitle 返回大纲项的标题，返回的是html（注意文本要转义，如果包含a标签需要替换成其他标签）
 * @param {boolean|string}rootIndent 根元素缩进，默认不缩进，true使用默认1.5em，或者指定缩进数量
 * @param {number}collapseMaxLength 最大子列表内长度，超过则改成details折叠列表
 * @returns {HTMLUListElement} 一个ul元素，表示大纲树的根节点
 */
export function buildToc({
	getItems,
	getLevel = e=>+e.tagName[1],
	getTitle = e=>e.innerHTML,
	rootIndent = false,
	collapseMaxLength = 30,
}){
	const items = getItems();
	let i = 0;
	
	if (items.length===0){
		return $(`<ul class="viocha-toc"></ul>`)[0];
	} // 返回空列表
	
	const minLevel = Math.min(...items.map(getLevel));
	const $tocUl = build(minLevel).addClass('viocha-toc-root');
	addTocCss();
	return $tocUl[0];
	
	// 生成层级为level的ul
	function build(level){
		const $ul = $(`<ul class="viocha-toc level-${level}" >`);
		
		while (i<items.length && getLevel(items[i])>=level){
			const item = items[i];
			
			const itemLevel = getLevel(item);
			if (itemLevel===level){
				const $a = $('<a class="viocha-toc-anchor">');
				$a.attr('href', '#'+getId(item)); // 设置目标
				$a.append(getTitle(item)); // 设置标题内容
				
				const $li = $(`<li class="viocha-toc-item level-${level}">`);
				$ul.append($li.append($a));
				i++;
			} else if (itemLevel>level){
				let $subList;
				if (itemLevel<=6){
					$subList = build(level+1);
				}// level+1能处理层级跳跃的大纲
				else {
					$subList = build(itemLevel);
				}
				
				let $last = $ul.children().eq(-1);
				
				if ($last.is('li')){ // 未添加同级子列表
					if ($subList.children().length<=collapseMaxLength){
						$ul.append($subList);
					} else if ($subList.is(`.level-${level+1}`)){
						foldUl($last, $subList);
					} else { // 未填充的跳跃子列表，创建一个虚拟的下一个层级ul作为容器
						const $dummyUl = $(`<ul class="viocha-toc level-${level+1}">`);
						const $li = $(`<li class="viocha-toc-item level-${level+1}">[详细内容]</li>`);
						$dummyUl.append($li);
						
						$ul.append($dummyUl);
						foldUl($li, $subList);
					}
				} else if ($last.is('details')){
					$last.children('ul').append($subList.children()); // 已经添加了一个同级子列表，且已折叠
				} else if ($last.is('ul')){ // 已经添加同级子列表，但未折叠
					$last.append($subList.children());
					if ($last.children().length>collapseMaxLength){
						foldUl($last.prev(), $last);
					}
				} else if ($last.length===0){ // 当前是被跳过的层级
					if ($subList.children().length<=collapseMaxLength){
						$ul.append($subList);
					} else { // 创建一个占位的li节点作为summary
						const $li = $(`<li class="viocha-toc-item level-${level}">[跳跃内容]</li>`);
						$ul.append($li);
						foldUl($li, $subList);
					}
				}
				// 不用i++，因为递归函数进行了相加
			}
		} // 循环结束时，i指向父层级项
		
		return $ul;
	}
	
	// 将li作为标题，ul作为内容，转换成折叠列表，并将li替换成新的details
	function foldUl($li, $subUl){
		const $details = $('<details>');
		$details.append($('<summary class="viocha-toc-summary">').append($li.html()));
		$details.append($subUl);
		$li.replaceWith($details);
	}
	
	// 查询id或者生成一个id并返回
	function getId(item){
		if (item.id){
			return item.id;
		} // 如果已经有id，则不生成
		
		const text = item.textContent.trim().slice(0, 20);
		let id = CSS.escape(text).replaceAll(/\\./g, '_'); // 转义
		id += '_'+Math.random().toString(36).slice(2, 10); // 添加随机数字
		
		item.id = id;
		return id;
	}
	
	// 添加toc样式
	function addTocCss(){
		if ($('style#viocha-toc-css').length>0){
			return;
		}
		
		let cssText = /* language=css */ `
      /* 字体大小，行高 */
      .viocha-toc-root :is(.viocha-toc-summary,.viocha-toc-item,.viocha-toc-anchor) {
        font-size   : 13px !important;
        line-height : 1.2 !important;
      }

      /* 嵌套列表缩进 */
      ul.viocha-toc:not(.viocha-toc-root) { /* details的子元素通过全局样式缩进 */
        margin : 0 0 0 1.5em !important;
      }

      /* 不显示列表标记 */
      .viocha-toc-root li.viocha-toc-item {
        list-style-type : none !important;
        margin-left     : 0 !important;
      }

      /* 设置li和summary的最小宽度为内容长度 */
      .viocha-toc-root :is(.viocha-toc-item, .viocha-toc-summary) {
        min-width : max-content !important;
      }

      /* 链接悬浮样式 */
      .viocha-toc-root .viocha-toc-item > a.viocha-toc-anchor { /* 不包含summary当中的a标签，summary的子元素应该是inline的 */
        display              : block !important;
        text-decoration-line : none !important;
      }

      .viocha-toc-root a.viocha-toc-anchor:hover { /* 不添加透明系数，可能会重叠 */
        background-color     : #ebf8f6 !important;
        text-decoration-line : underline !important;
        font-weight          : bold !important;
      }
		
		`;
		
		// 根列表缩进
		let indent = '0';
		if (rootIndent.constructor===Boolean && rootIndent){
			indent = '1.5em';
		}//
		else if (rootIndent.constructor===String){
			indent = rootIndent;
		}
		
		cssText += /* language=css */ `
      ul.viocha-toc.viocha-toc-root {
        margin-left : ${indent} !important;
      }
		`;
		
		GM_addElement('style', {
			id:'viocha-toc-css', // language=css
			textContent:cssText,
		});
	}
}

// 折叠内容，在content所在位置包裹一个details元素，并将header移动到其中作为summary，返回details元素
/**
 * @param {string|HTMLElement|JQuery} content 在页面上需要折叠的内容，可以是多个元素
 * @param {string|HTMLElement|JQuery} header 折叠列表的标题，可以是新创建的不在页面中的元素
 * @param {boolean}isOpen 默认是否展开
 */
export function collapse(content, header, isOpen = false){
	const $content = $(content);
	const $header = $(header).css('display', 'inline'); // 防止折叠标题和图标之间换行
	const $details = $content.wrapAll('<details>').parent();
	$header.prependTo($details).wrap('<summary>');
	
	$details.prop('open', isOpen);
	return $details[0];
}

/**
 * 创建折叠按钮，一键折叠和展开某个容器下的所有details
 * - __依赖 `addButtonCss` 函数__
 * @param {string|HTMLElement|JQuery?} container 容器的选择器或容器元素，默认为body
 * @returns {HTMLButtonElement} 返回一个button元素，用于添加到页面上
 */
export function createCollapseButton(container = 'html body'){
	const $button = $('<button class="viocha-button" title="左键切换，中间折叠，右键展开">折叠/展开</button>');
	$button.on('contextmenu', ()=>false);
	$button.on('mousedown', event=>{
		let open = !getOpenStatus();
		if (event.which===2){
			open = false;
		} // 中间强制折叠
		if (event.which===3){
			open = true;
		}  // 右键强制展开
		$(container).find('details').prop('open', open);
		return false;
	});
	
	// 添加按钮的样式
	addButtonCss();
	
	return $button[0];
	
	// 判断折叠状态，超过半数展开视作全部展开
	function getOpenStatus(){
		let open = 0, close = 0;
		$(container).find('details').each((_, e)=>{
			if (e.open){
				open++;
			} else {
				close++;
			}
		});
		return open>=close;
	}
}

// 添加viocha-button类的按钮的样式，可以多次添加，仅第一次生效
export function addButtonCss(){
	if ($('style#viocha-button-css').length>0){
		return;
	}
	GM_addElement('style', {
		id:'viocha-button-css', // language=css
		textContent:`
      button.viocha-button {
        margin        : 0 0.5em !important;
        border-radius : 0.5em !important;
        border        : 1px solid rgba(204, 204, 204, 0.9) !important;
        font-size     : 0.8rem !important;
      }

      button.viocha-button:hover {
        background-color : rgba(204, 204, 204, 0.65) !important;
      }

      button.viocha-button:active {
        background-color : rgba(204, 204, 204, 1) !important;
      }
		`,
	});
}

/**
 * 高亮离页面顶部最近的TOC标题链接
 * - __依赖 `scrollRelativeToViewTop` 函数__
 * @param {string|HTMLElement|JQuery} anchorSelector 需要监听的标题元素对应的链接
 * @returns {IntersectionObserver} 返回observer用于取消
 */
export function highlightCurrentTocHeading(anchorSelector){
	const idToAnchor = {};
	let lastScrollTime = 0; // 上次滚动的时间，200ms内只滚动一次
	const observer = new IntersectionObserver(entries=>{
				entries = entries.filter(e=>e.isIntersecting);
				if (entries.length===0){
					return;
				}
				
				const {target} = entries[0];
				$(anchorSelector).filter('a.viocha-toc-current').removeClass('viocha-toc-current');
				const anchor = idToAnchor[target.id];
				// 展开父节点所有details，然后高亮
				$(anchor).parents('details').prop('open', true);
				$(anchor).addClass('viocha-toc-current');
				
				// 当链接超出可见区域，滚动链接到中间
				if (Date.now()-lastScrollTime<200){
					return;
				} else {
					lastScrollTime = Date.now();
				}
				
				const scrollParent = getScrollParent(anchor);
				const viewOffset = anchor.getBoundingClientRect().top-scrollParent.getBoundingClientRect().top;
				if (viewOffset<16 || viewOffset>scrollParent.clientHeight-16){ // scrollIntoView平滑滚动不会生效，用JQuery
					scrollRelativeToViewTop(anchor, '50%', {container:scrollParent});
				}
				
			}, // 限制在10%到30%高度之间触发
			{rootMargin:'-10% 0px -70% 0px'});
	
	$(anchorSelector).each((_, anchor)=>{
		const id = $(anchor).attr('href').split('#')[1]; // 使用attr才不会对中文转码
		idToAnchor[id] = anchor;
		observer.observe($('#'+escapeCss(id))[0]); // 监听每个标题元素，注意选择器需要转义
		
		// 让toc链接点击时也能高亮
	}).on('click', event=>{
		setTimeout(()=>{
			$(anchorSelector).filter('a.viocha-toc-current').removeClass('viocha-toc-current');
			$(event.currentTarget).addClass('viocha-toc-current');
		}, 10); // 等待observer响应完
	});
	
	// 添加当前标题链接的样式
	addHighlightedCss();
	
	// 滚动到当前锚点位置
	setTimeout(()=>{
		const curAnchor = $('a.viocha-toc-current')[0];
		if (!curAnchor){
			return;
		}
		curAnchor.scrollIntoView({block:'center'});
		getScrollParent(curAnchor, 'h').scrollTo({'left':0});
	}, 1500);
	
	// 返回observer用于取消
	return observer;
	
	/**
	 * 获取最近的可滚动父元素，滚动的距离大于5px且overflow不等于visible和hidden视为可滚动
	 * @param {HTMLElement} element 从该元素的父元素开始向上寻找
	 * @param {'v'|'h'='v'} direction 需要判断的滚动方向，默认为垂直
	 * @returns {HTMLElement}
	 */
	function getScrollParent(element, direction = 'v'){
		let isScrollable = e=>{
			if (Math.abs(e.scrollHeight-e.clientHeight)<=5){
				return false;
			}
			const overflowY = getComputedStyle(e).overflowY;
			return overflowY==='auto' || overflowY==='scroll'; // 只有这两种情况允许用户滚动
		};
		if (direction==='h'){
			isScrollable = e=>{
				if (Math.abs(e.scrollWidth-e.clientWidth)<=5){
					return false;
				}
				const overflowX = getComputedStyle(e).overflowX;
				return overflowX==='auto' || overflowX==='scroll';
			};
		}
		
		let parent = element.parentElement;
		while (parent!==document.body && !isScrollable(parent)){
			parent = parent.parentElement;
		}
		return parent;
	}
	
	// 添加链接高亮的样式
	function addHighlightedCss(){
		if ($('style#viocha-toc-current-css').length>0){
			return;
		}
		GM_addElement('style', {
			id:'viocha-toc-current-css', // language=css
			textContent:`
        a.viocha-toc-current { /* 注意：链接可能显示为inline，则无法高亮整行 */
          background-color : rgb(255 200 236 / 31%) !important;
        }
			`,
		});
	}
}

/**
 * 将元素滚动到距container视图上方距离为top的位置
 * @param {HTMLElement|JQuery|string}element 容器的子元素
 * @param {string|number}top 可以是数字，代表像素值；可以是相对于容器高度的百分比；可以是相对于element的字体的长度em
 * @param {object?}options 其他选项
 * @param {HTMLElement|JQuery|string?}options.container 可以垂直滚动的容器，默认为offsetParent
 * @param {object?}options.animateOptions js滚动动画参数，默认为{duration:200}
 */
export function scrollRelativeToViewTop(element, top, options = {}){
	let {container, animateOptions} = options;
	animateOptions = Object.assign({duration:200}, animateOptions); // 默认动画参数
	
	element = $(element)[0];
	if (!container){
		container = element.offsetParent;
	} else {
		container = $(container)[0];
	}
	
	const topPixel = getTopPixel(top);
	const viewOffset = element.getBoundingClientRect().top-container.getBoundingClientRect().top; // 视图高度差
	const scrollTop = container.scrollTop+viewOffset-topPixel; // 计算最终的scrollTop，注意移动方向和scrollTop变化方向相反
	
	$(container).animate({scrollTop, ...animateOptions});//
	
	// top的单位转换成像素
	function getTopPixel(top){
		if (top.constructor===Number){
			return top;
		}
		if (top.endsWith('em')){
			const emInPx = +getComputedStyle(element).fontSize.slice(0, -2); // 获取字体大小
			return parseFloat(top.slice(0, -2))*emInPx;
		} else if (top.endsWith('%')){
			return parseFloat(top.slice(0, -1))/100*container.clientHeight;
		}
	}
}

/**
 * 使用 UnoCSS 引擎编译包含 @apply 等指令的 CSS 字符串。
 * 这个函数是自包含的，它会在内部动态加载所有必要的依赖。
 * 需要添加依赖
 // @require     https://cdn.jsdelivr.net/npm/magic-string/dist/magic-string.umd.min.js
 // @require     https://cdn.jsdelivr.net/npm/unocss-compiler@1.0.0/dist/unocss-compiler.umd.min.js *
 * @param {string} cssString - 需要编译的 CSS 字符串。
 * @param {object} [options={}] - 配置选项。
 * @param {string} [options.prefix='un-'] - 自定义 UnoCSS 生成的 CSS 变量前缀。
 * @param {boolean} [options.preflight=true] - 是否在最终输出中包含 preflight 全局样式。
 * @returns {Promise<string>} - 返回编译完成的 CSS 字符串。
 */
async function compileCss(cssString, options = {}){
	// 参数校验
	if (typeof cssString!=='string'){
		console.error('Error: compileCss expects a string as the first argument.');
		return '';
	}
	const {transformerDirectives, createGenerator, presetWind} = unocssCompiler;
	if (!transformerDirectives || !createGenerator || !presetWind){
		throw new Error('UnoCSS compiler dependencies are not loaded');
	}
	
	// 解构简洁的选项名称
	const {
		prefix = 'un-',
		preflight = true,
	} = options;
	
	// 创建 UnoCSS 实例
	const uno = await createGenerator({
		presets:[
			presetWind({
				variablePrefix:prefix, // 使用 'prefix' 选项
			}),
		],
		transformers:[
			transformerDirectives(),
		],
	});
	
	const s = new MagicString(cssString);
	const directiveTransformer = uno.config.transformers.find(t=>t.name==='@unocss/transformer-directives');
	if (directiveTransformer){
		await directiveTransformer.transform(s, 'style.css', {uno});
	}
	const compiledDirectivesCss = s.toString();
	
	// 根据 'preflight' 选项决定最终输出
	if (preflight){
		const {css:preflights} = await uno.generate('');
		return preflights+'\n'+compiledDirectivesCss;
	} else {
		return compiledDirectivesCss;
	}
}

// 编译UnoCSS样式并添加到页面，默认使用vh-前缀，避免冲突
async function addUnoCss(cssString){
	const compiledCss = await compileCss(cssString, {preflight:false, prefix:'vh-'});
	GM_addStyle(compiledCss);
	
	// 添加preflight样式，仅添加一次
	if (!$('#vh-uno-preflight').length){
		const preflightCss = await compileCss('', {preflight:true, prefix:'vh-'});
		if (!$('#vh-uno-preflight').length){
			GM_addElement('style', {
				id:'vh-uno-preflight',
				textContent:preflightCss,
			});
		}
	}
}

/**
 * 动态加载并初始化一个独立的、带前缀的 UnoCSS 运行时。
 * 此函数是健壮且幂等的，可以安全地被并发调用。
 *
 * 默认使用 'vh-' 作为 CSS 工具类的前缀，以避免与页面上已有的类名冲突。
 * 默认会为所有生成的规则添加 !important，以确保样式优先级。
 *
 * 此版本使用 GM_getResourceText 和 eval，因为中间需要配置。
 * 确保已经添加如下资源:
 // @resource     unoPresetWindJS https://cdn.jsdelivr.net/npm/@unocss/runtime/preset-wind.global.js
 // @resource     unoCoreJS       https://cdn.jsdelivr.net/npm/@unocss/runtime/core.global.js
 *
 * @param {object} [options={}] - 配置对象。
 * @param {string} [options.prefix='vh-'] - CSS 工具类的前缀。
 * @param {boolean} [options.important=true] - 为所有规则添加 !important。
 * @param {object} [options.theme={}] - 自定义或扩展主题。
 *
 * @returns {Promise<boolean>} - 如果成功加载或已加载则返回 true，加载失败则返回 false。
 */
async function loadUno(options = {}){
	// 使用 unsafeWindow 存储跨脚本的状态
	const pageWindow = unsafeWindow;
	
	// --- 使用硬编码的实例 ID 确保状态键的唯一性 ---
	const instanceId = 'viocha-unocss';
	const configLoadedKey = `__uno_loaded_${instanceId}`; // 是否已经成功加载
	const loadingPromiseKey = `__uno_loading_${instanceId}`; // 加载中的 Promise
	
	// 在 pageWindow 上检查实例是否已存在或正在加载
	if (pageWindow[configLoadedKey]){
		return true;
	}
	if (pageWindow[loadingPromiseKey]){
		return pageWindow[loadingPromiseKey];
	}
	
	// 2. 将加载 Promise 存储在 pageWindow 上以处理并发调用
	const loadingPromise = (async()=>{
		try {
			const presetWindScript = GM_getResourceText('unoPresetWindJS');
			const coreScript = GM_getResourceText('unoCoreJS');
			
			if (!presetWindScript || !coreScript){
				throw new Error('UnoCSS resource scripts not found. Make sure @resource is defined correctly.');
			}
			
			// 准备配置
			const config = {
				prefix:'vh-', // 默认使用vh前缀，避免冲突
				important:true, // 默认添加important
				theme:{},
				...options,
			};
			const {theme, ...presetOptions} = config;
			
			// 在沙箱(window)中执行 preset-wind 脚本，它会定义 window.__unocss_runtime
			eval(presetWindScript);
			
			if (!window.__unocss_runtime?.presets?.presetWind){
				throw new Error('UnoCSS preset-wind failed to initialize in the sandboxed window.');
			}
			
			// 在沙箱(window)上设置 __unocss 配置
			// UnoCSS 核心运行时会自动读取此变量
			window.__unocss = {
				presets:[
					window.__unocss_runtime.presets.presetWind(presetOptions),
				],
				theme:theme || {},
			};
			
			// 在沙箱中执行核心运行时脚本
			eval(coreScript);
			
			// 在 pageWindow 上设置成功标志
			pageWindow[configLoadedKey] = true;
			return true;
		} catch (error){
			console.error('[UnoCSS] 加载失败:', error);
			return false;
		} finally {
			delete pageWindow[loadingPromiseKey]; // 任务完成后，无论成功与否，都从 pageWindow 删除加载承诺的键
		}
	})();
	
	pageWindow[loadingPromiseKey] = loadingPromise;
	return loadingPromise;
}
